(function() {

    var
    $u = juliet.using({
        i18n : 'juliet.i18n.i18n-0.1',
        validationResult : 'juliet.validation.validationResult',
        validationEvent : 'juliet.validation.validationEvent'
    }),
    ve = $u('validationEvent'),
    vr = $u('validationResult');

    /**
     * Contains all validators classes and factory that creates new validators objects
     */
    var validatorObject = {

        addValidator : function(name, clazz) {
            this[name] = clazz;
            logger.debug('Validator %s added.', name);
        }

    };

    /**
     * Creates new validators objects
     */
    validatorObject.factory = {

        create : function(name) {
            var
            validatorClass = validatorObject[name],
            isPrototypeCorrect = (validatorClass.prototype instanceof validatorObject.BaseValidator);

            if (!isPrototypeCorrect) validatorClass.prototype = new validatorObject.BaseValidator();

            var validatorInstance = new validatorClass();
            validatorInstance.base = validatorClass.prototype;

            return validatorInstance;
        }

    };

    /**
     * Base validator
     */
    validatorObject.BaseValidator = function() {

        this.active = true;
        this.uid = null;
        this.chain = null;
        this.metadata = null;
        this.previous = null;
        this.next = null;
        this.errorText = null;
        this.result = vr.UNKNOWN;
        this.validationEvents = ve.CHANGE;

        this.initialize = function(o) {
            this.uid = o.uid;
            this.chain = o.chain;
            this.metadata = o.metadata;
            this.previous = o.previous;
            this.next = o.next;
            this.errorText = this.getOptionValue('errorText');

            this.validationEvents = this.getOptionValue('validationEvents') || this.validationEvents;
        };

        this.getOptionValue = function(name) {
            if (!this.metadata.options) return null;
            return this.metadata.options[name];
        };

        this.isSupportValidationEvent = function(validationEvent) {
            return ((this.validationEvents & validationEvent) == validationEvent);
        };

        this.getError = function(messageKey, o) {
            if (this.getOptionValue('suppressError')) return { suppress : true };

            if (this.metadata.suppressErrorOnce) {
                delete this.metadata.suppressErrorOnce;
                return { suppress : true };
            }

            var
            errorTextEmpty = (typeof this.errorText == 'undefined') || (this.errorText == null),
            text = (errorTextEmpty ? $u('i18n').get(messageKey) : this.errorText),
            locale = this.chain.manager.locale;

            if (text[locale]) text = text[locale];

            if (o) {
                for (var option in o) {
                    if (o[option] != undefined) text = text.replace('${' + option + '}', o[option]);
                }
            }

            var forceErrorOnce = false;

            if (this.metadata.forceErrorOnce) {
                delete this.metadata.forceErrorOnce;
                forceErrorOnce = true;
            }

            return { text : text, force : (this.getOptionValue('forceError') || forceErrorOnce) };
        };

    };

    juliet.registerModule('juliet.validation', 'validator', validatorObject);

})();
